#pragma once
#include <sys/select.h>
#include "Socket.hpp"
#include "Log.hpp"
#include <memory>
#include <errno.h>
#include <string.h>
#include <string>

static const int num = sizeof(fd_set) * 8;
class SelectServer
{
public:
    SelectServer(uint16_t port)
        :_port(port), _listensock(new TcpSocket), _isrunning(false)
    {
    }
    void Init()
    {
        for(int i = 0; i < num; i++)
            _rfds[i] = nullptr;

        _listensock->CreateListenSocket(_port);
        _rfds[_listensock->GetSockfd()] = _listensock.get();

        _isrunning = true;
    }
    void PrintDebug()
    {
        std::cout << "关心的读事件的fd: ";
        for(int i = 0; i < num; i++)
            if(_rfds[i])
                std::cout << i << " ";
        std::cout << std::endl;
    }
    void Loop()
    {
        while(_isrunning)
        {
            fd_set fds;
            FD_ZERO(&fds);  
            int max_fd = 0;
            for(int i = 0; i < num; i++)
            {
                if(_rfds[i])
                {
                    FD_SET(i, &fds);
                    max_fd = i;
                }
            }
            struct timeval timeval = {5, 0};
            int n = select(max_fd + 1, &fds, nullptr, nullptr, &timeval);
            PrintDebug();
            if(n == 0)
                lg.LogMessage(Warning, "timeout...\n");
            else if(n == -1)
            {
                // if(errno == EWOULDBLOCK)
                //     lg.LogMessage(Warning, "读事件没就绪\n");
                // else if(errno == EINTR)
                //     lg.LogMessage(Warning, "被信号中断\n");
                // else lg.LogMessage(Error, "select 错误\n");
                lg.LogMessage(Error, "select 错误, errno: %d: %s\n", errno, strerror(errno));
            }
            else
            {
                lg.LogMessage(Info, "select success, %d, %d\n", timeval.tv_sec, timeval.tv_usec);
                HandlerEvent(fds);
            }
        }
    }
    void HandlerEvent(const fd_set& fds)
    {
        for(int i = 0; i < num; i++)
        {
            if(_rfds[i] && FD_ISSET(i, &fds))   //fd是否被关心 && fd事件是否就绪
            {
                if(i == _listensock->GetSockfd()) //listensockfd
                {
                    std::string clientip;
                    uint16_t clientport;
                    Socket* sock = _listensock->AcceptConnection(clientip, clientport);
                    int fd = sock->GetSockfd();
                    if(fd < num)
                    {
                        _rfds[sock->GetSockfd()] = sock;   
                        lg.LogMessage(Info, "connect sccess, fd:%d\n", fd);
                    }
                    else
                    {
                        sock->CloseSockfd();
                        delete sock;
                        lg.LogMessage(Error, "fd full\n");
                    }
                }
                else
                {
                    Socket* sock = _rfds[i];
                    std::string request = sock->Recv();
                    if(!request.empty())
                    {
                        // request += "!!!";
                        sock->Send(request);
                    }
                    else
                    {
                        lg.LogMessage(Warning, "client quit\n");
                        _rfds[i] = nullptr;

                        sock->CloseSockfd();
                        delete sock;
                    }
                }
            } 
        }
    }
    ~SelectServer()
    {
    }
private:
    std::unique_ptr<Socket> _listensock;
    uint16_t _port;
    bool _isrunning;
    Socket* _rfds[num];     //读的合集,fd直接与下标对应
};